#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <signal.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <server_conf.h>
#include <threadpool.h>
#include <nodelist.h>
#include <work.h>
#include <heartBeat.h>
#include <sql.h>

static int lfd;
PT_threadPool g_pthreadPool=NULL;

/*
*	函数功能：		创建守护进程
*	函数参数	：	无
*	函数返回值：创建守护进程是否成功
*				成功：0
*				失败：<0
*/
static int daemon_init()
{
	pid_t pid;
	int fd;

	pid = fork();
	if(pid<0)
	{
		syslog(LOG_ERR,"daemon_init fork error");
		return -1;
	}
	
	if(pid>0)
	{
		exit(0);
	}
	else
	{
		fd = open("/dev/null",O_RDWR);
		if(fd <0)
		{
			syslog(LOG_ERR,"daemon_init open error");
			return -2;
		}
		dup2(0,fd);
		dup2(1,fd);
		dup2(2,fd);
		if(fd>2)
			close(fd);
		setsid();
		chdir("/");
		umask(0);
	}
	return 0;
}

/*
*	函数功能：		网络初始化
*	函数参数	：	无
*	函数返回值：网络初始化是否成功
*				成功：0
*				失败：<0
*/
static int socket_init(void)
{
	int value;
	int ret;
	struct sockaddr_in laddr;

	lfd = socket(AF_INET,SOCK_STREAM,0);
	if(lfd <0)
	{
		syslog(LOG_ERR,"socket_init socket error %s",strerror(errno));
		return -1;
	}

	value =1;
	ret = setsockopt(lfd,SOL_SOCKET,SO_REUSEADDR,&value,sizeof(value));
	if(ret <0)
	{
		syslog(LOG_ERR,"socket_init setsockopt addr error %s",strerror(errno));
		return -2;
	}

	value =1;
	ret = setsockopt(lfd,SOL_SOCKET,SO_REUSEPORT,&value,sizeof(value));
	if(ret <0)
	{
		syslog(LOG_ERR,"socket_init setsockopt port error %s",strerror(errno));
		return -3;
	}

	//绑定端口与地址
	laddr.sin_family = AF_INET;
	laddr.sin_port = htons(atoi(SERVER_PORT));
	inet_pton(AF_INET,"0.0.0.0",&laddr.sin_addr.s_addr);
	ret = bind(lfd,(void *)&laddr,sizeof(laddr));
	if(ret <0)
	{
		syslog(LOG_ERR,"socket_init bind error %s",strerror(errno));
		return -4;
	}

	//监听
	ret = listen(lfd,200);
	if(ret <0)
	{
		syslog(LOG_ERR,"socket_init listen error %s",strerror(errno));
		return -5;
	}	

	return 0;
}

/*
*	函数功能：		信号处理函数
*	函数参数	：	获取到的信号
*	函数返回值：无
*/
static void exit_handler(int s)
{
	syslog(LOG_DEBUG,"get signal %d exiting.",s);

	//销毁sql连接池
	sql_connPoolDestory();

	//销毁nodeList
	nodeList_destroy();
	
	//退出epoll线程
	threadPool_destroy(g_pthreadPool);

	close(lfd);
	syslog(LOG_DEBUG,"lfd close sucess");

	closelog();
	syslog(LOG_DEBUG,"syslog close sucess");

	exit(0);
}

int main()
{
	int ret;
	int clientfd;
	char ip[20];
	struct sockaddr_in raddr;
	socklen_t rlenth = sizeof(raddr);
	struct sigaction act;

	//设置信号处理函数
	act.sa_handler = exit_handler;
	sigemptyset(&act.sa_mask);
	sigaddset(&act.sa_mask,SIGINT);
	sigaddset(&act.sa_mask,SIGQUIT);
	sigaddset(&act.sa_mask,SIGTERM);
	act.sa_flags =0;

	sigaction(SIGINT,&act,NULL);
	sigaction(SIGQUIT,&act,NULL);
	sigaction(SIGTERM,&act,NULL);

	//设置系统日志
	openlog("server",LOG_PID|LOG_PERROR,LOG_DAEMON);

	//创建守护进程
	if(RUNNINGMODE == DAEMON)
	{
		ret = daemon_init();
		if(ret <0)
		{
			syslog(LOG_ERR,"daemon_init error");
			exit(1);
		}
	}
	else if(RUNNINGMODE == NORMAL)
	{
		//do something
	}
	else
	{
		syslog(LOG_ERR,"running in unkown mode");
		exit(1);
	}

	//网络初始化
	ret = socket_init();
	if(ret <0)
	{
		syslog(LOG_ERR,"socket init error");
		exit(1);
	}

	//创建sql连接池
	ret = sql_connPoolInit();
	if(ret <0)
	{
		syslog(LOG_ERR,"sql init error");
		exit(1);
	}

	//初始化nodeList
	ret = nodeList_init();
	if(ret <0)
	{
		syslog(LOG_ERR,"nodeList init error");
		exit(1);
	}

	//初始化nodeList心跳
	heartbeatInit();

	//初始化静态线程池
	g_pthreadPool = threadPool_init(func_handler);
	if(g_pthreadPool ==NULL)
	{
		syslog(LOG_ERR,"threadPool init error");
		exit(1);
	}

	//显示当前软件版本
	syslog(LOG_DEBUG,"%s",VERSION);

	while(1)
	{
		//等待客户端连接
		clientfd = accept(lfd,(void *)&raddr,&rlenth);
		if(clientfd <0)
		{
			if(errno == EAGAIN || errno == EINTR)
				continue;
			syslog(LOG_ERR,"accept error %s",strerror(errno));
			continue;
		}

#if DEBUG
		//显示客户端信息
		memset(ip,0,sizeof(ip));
		inet_ntop(AF_INET,&raddr.sin_addr.s_addr,ip,sizeof(ip));
		syslog(LOG_DEBUG,"clientIP:%s clientPORT:%d",ip,ntohs(raddr.sin_port));		
#endif

		//添加客户端到epoll监控	
		ret = threadPool_addjob(g_pthreadPool,clientfd);
		if(ret<0)
		{
			close(clientfd);
			syslog(LOG_ERR,"threadPool addjob error");
		}
	}

	exit(0);
}

